1 /**
2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module code_checker.engine.builtin.clang_tidy_classification;
7 
8 public import code_checker.engine.types : Severity;
9 
10 @safe:
11 
12 struct SeverityColor {
13     import colorize : Color, Background, Mode;
14 
15     Color c = Color.white;
16     Background bg = Background.black;
17     Mode m;
18 }
19 
20 immutable Severity[string] diagnosticSeverity;
21 immutable SeverityColor[Severity] severityColor;
22 
23 shared static this() {
24     // copied from https://github.com/Ericsson/codechecker/blob/master/config/checker_severity_map.json
25 
26     // sorted alphabetically
27 
28     // dfmt off
29     diagnosticSeverity = [
30         // these do not seem to exist. keeping if they are impl. in clang-tidy
31     "alpha.clone.CloneChecker":                                   Severity.low,
32     "alpha.core.BoolAssignment":                                  Severity.low,
33     "alpha.core.CallAndMessageUnInitRefArg":                      Severity.high,
34     "alpha.core.CastSize":                                        Severity.low,
35     "alpha.core.CastToStruct":                                    Severity.low,
36     "alpha.core.Conversion":                                      Severity.low,
37     "alpha.core.FixedAddr":                                       Severity.low,
38     "alpha.core.IdenticalExpr":                                   Severity.low,
39     "alpha.core.PointerArithm":                                   Severity.low,
40     "alpha.core.PointerSub":                                      Severity.low,
41     "alpha.core.SizeofPtr":                                       Severity.low,
42     "alpha.core.TestAfterDivZero":                                Severity.medium,
43     "alpha.cplusplus.DeleteWithNonVirtualDtor":                   Severity.high,
44     "alpha.cplusplus.IteratorRange":                              Severity.medium,
45     "alpha.cplusplus.MisusedMovedObject":                         Severity.medium,
46     "alpha.deadcode.UnreachableCode":                             Severity.low,
47     "alpha.osx.cocoa.DirectIvarAssignment":                       Severity.low,
48     "alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions":  Severity.low,
49     "alpha.osx.cocoa.InstanceVariableInvalidation":               Severity.low,
50     "alpha.osx.cocoa.MissingInvalidationMethod":                  Severity.low,
51     "alpha.osx.cocoa.localizability.PluralMisuseChecker":         Severity.low,
52     "alpha.security.ArrayBound":                                  Severity.high,
53     "alpha.security.ArrayBoundV2":                                Severity.high,
54     "alpha.security.MallocOverflow":                              Severity.high,
55     "alpha.security.ReturnPtrRange":                              Severity.low,
56     "alpha.unix.BlockInCriticalSection":                          Severity.low,
57     "alpha.unix.Chroot":                                          Severity.medium,
58     "alpha.unix.PthreadLock":                                     Severity.high,
59     "alpha.unix.SimpleStream":                                    Severity.medium,
60     "alpha.unix.Stream":                                          Severity.medium,
61     "alpha.unix.cstring.BufferOverlap":                           Severity.high,
62     "alpha.unix.cstring.NotNullTerminated":                       Severity.high,
63     "alpha.unix.cstring.OutOfBounds":                             Severity.high,
64     // ---
65     "android-cloexec-creat":                                      Severity.medium,
66     "android-cloexec-fopen":                                      Severity.medium,
67     "android-cloexec-open":                                       Severity.medium,
68     "android-cloexec-socket":                                     Severity.medium,
69     "boost-use-to-string":                                        Severity.low,
70     "bugprone-argument-comment":                                  Severity.low,
71     "bugprone-assert-side-effect":                                Severity.medium,
72     "bugprone-bool-pointer-implicit-conversion":                  Severity.low,
73     "bugprone-copy-constructor-init":                             Severity.medium,
74     "bugprone-dangling-handle":                                   Severity.high,
75     "bugprone-fold-init-type":                                    Severity.high,
76     "bugprone-forward-declaration-namespace":                     Severity.low,
77     "bugprone-inaccurate-erase":                                  Severity.high,
78     "bugprone-integer-division":                                  Severity.medium,
79     "bugprone-misplaced-operator-in-strlen-in-alloc":             Severity.medium,
80     "bugprone-misplaced-operator-in-strlen-in-alloc":             Severity.medium,
81     "bugprone-move-forwarding-reference":                         Severity.medium,
82     "bugprone-multiple-statement-macro":                          Severity.medium,
83     "bugprone-string-constructor":                                Severity.high,
84     "bugprone-suspicious-memset-usage":                           Severity.high,
85     "bugprone-undefined-memory-manipulation":                     Severity.medium,
86     "bugprone-use-after-move":                                    Severity.high,
87     "bugprone-virtual-near-miss":                                 Severity.medium,
88     "cert-dcl03-c":                                               Severity.medium,
89     "cert-dcl21-cpp":                                             Severity.low,
90     "cert-dcl50-cpp":                                             Severity.low,
91     "cert-dcl54-cpp":                                             Severity.medium,
92     "cert-dcl58-cpp":                                             Severity.high,
93     "cert-dcl59-cpp":                                             Severity.medium,
94     "cert-env33-c":                                               Severity.medium,
95     "cert-err09-cpp":                                             Severity.high,
96     "cert-err34-c":                                               Severity.low,
97     "cert-err52-cpp":                                             Severity.low,
98     "cert-err58-cpp":                                             Severity.low,
99     "cert-err60-cpp":                                             Severity.medium,
100     "cert-err61-cpp":                                             Severity.high,
101     "cert-fio38-c":                                               Severity.high,
102     "cert-flp30-c":                                               Severity.high,
103     "cert-msc30-c":                                               Severity.low,
104     "cert-msc50-cpp":                                             Severity.low,
105     "cert-oop11-cpp":                                             Severity.medium,
106     "clang-analyzer-core.CallAndMessage":                         Severity.high,
107     "clang-analyzer-core.DivideZero":                             Severity.high,
108     "clang-analyzer-core.DynamicTypePropagation":                 Severity.medium,
109     "clang-analyzer-core.NonNullParamChecker":                    Severity.high,
110     "clang-analyzer-core.NullDereference":                        Severity.high,
111     "clang-analyzer-core.StackAddressEscape":                     Severity.high,
112     "clang-analyzer-core.UndefinedBinaryOperatorResult":          Severity.medium,
113     "clang-analyzer-core.VLASize":                                Severity.medium,
114     "clang-analyzer-core.builtin.BuiltinFunctions":               Severity.medium,
115     "clang-analyzer-core.builtin.NoReturnFunctions":              Severity.medium,
116     "clang-analyzer-core.uninitialized.ArraySubscript":           Severity.medium,
117     "clang-analyzer-core.uninitialized.Assign":                   Severity.medium,
118     "clang-analyzer-core.uninitialized.Branch":                   Severity.medium,
119     "clang-analyzer-core.uninitialized.CapturedBlockVariable":    Severity.medium,
120     "clang-analyzer-core.uninitialized.UndefReturn":              Severity.high,
121     "clang-analyzer-cplusplus.NewDelete":                         Severity.high,
122     "clang-analyzer-cplusplus.NewDeleteLeaks":                    Severity.high,
123     "clang-analyzer-cplusplus.SelfAssignment":                    Severity.medium,
124     "clang-analyzer-deadcode.DeadStores":                         Severity.low,
125     "cppcoreguidelines-c-copy-assignment-signature":              Severity.medium,
126     "cppcoreguidelines-interfaces-global-init":                   Severity.low,
127     "cppcoreguidelines-no-malloc":                                Severity.low,
128     "cppcoreguidelines-pro-bounds-array-to-pointer-decay":        Severity.low,
129     "cppcoreguidelines-pro-bounds-constant-array-index":          Severity.low,
130     "cppcoreguidelines-pro-bounds-pointer-arithmetic":            Severity.low,
131     "cppcoreguidelines-pro-type-const-cast":                      Severity.low,
132     "cppcoreguidelines-pro-type-cstyle-cast":                     Severity.low,
133     "cppcoreguidelines-pro-type-member-init":                     Severity.low,
134     "cppcoreguidelines-pro-type-reinterpret-cast":                Severity.low,
135     "cppcoreguidelines-pro-type-static-cast-downcast":            Severity.low,
136     "cppcoreguidelines-pro-type-union-access":                    Severity.low,
137     "cppcoreguidelines-pro-type-vararg":                          Severity.low,
138     "cppcoreguidelines-slicing":                                  Severity.low,
139     "cppcoreguidelines-special-member-functions":                 Severity.low,
140     "google-build-explicit-make-pair":                            Severity.medium,
141     "google-build-namespaces":                                    Severity.medium,
142     "google-build-using-namespace":                               Severity.style,
143     "google-default-arguments":                                   Severity.low,
144     "google-explicit-constructor":                                Severity.medium,
145     "google-global-names-in-headers":                             Severity.high,
146     "google-readability-braces-around-statements":                Severity.style,
147     "google-readability-casting":                                 Severity.low,
148     "google-readability-function-size":                           Severity.style,
149     "google-readability-namespace-comments":                      Severity.style,
150     "google-readability-redundant-smartptr-get":                  Severity.medium,
151     "google-readability-todo":                                    Severity.style,
152     "google-runtime-int":                                         Severity.low,
153     "google-runtime-member-string-references":                    Severity.low,
154     "google-runtime-memset":                                      Severity.high,
155     "google-runtime-operator":                                    Severity.medium,
156     "hicpp-braces-around-statements":                             Severity.style,
157     "hicpp-deprecated-headers":                                   Severity.low,
158     "hicpp-exception-baseclass":                                  Severity.low,
159     "hicpp-explicit-conversions":                                 Severity.low,
160     "hicpp-function-size":                                        Severity.low,
161     "hicpp-invalid-access-moved":                                 Severity.high,
162     "hicpp-member-init":                                          Severity.low,
163     "hicpp-move-const-arg":                                       Severity.medium,
164     "hicpp-named-parameter":                                      Severity.low,
165     "hicpp-new-delete-operators":                                 Severity.low,
166     "hicpp-no-array-decay":                                       Severity.low,
167     "hicpp-no-assembler":                                         Severity.low,
168     "hicpp-no-malloc":                                            Severity.low,
169     "hicpp-noexcept-move":                                        Severity.medium,
170     "hicpp-signed-bitwise":                                       Severity.low,
171     "hicpp-special-member-functions":                             Severity.low,
172     "hicpp-static-assert":                                        Severity.low,
173     "hicpp-undelegated-constructor":                              Severity.medium,
174     "hicpp-use-auto":                                             Severity.style,
175     "hicpp-use-emplace":                                          Severity.style,
176     "hicpp-use-equals-default":                                   Severity.low,
177     "hicpp-use-equals-delete":                                    Severity.low,
178     "hicpp-use-noexcept":                                         Severity.style,
179     "hicpp-use-nullptr":                                          Severity.low,
180     "hicpp-use-override":                                         Severity.low,
181     "hicpp-vararg":                                               Severity.low,
182     "llvm-header-guard":                                          Severity.low,
183     "llvm-include-order":                                         Severity.low,
184     "llvm-namespace-comment":                                     Severity.style,
185     "llvm-twine-local":                                           Severity.low,
186     "clang-analyzer-llvm.Conventions":                            Severity.low,
187     "misc-argument-comment":                                      Severity.low,
188     "misc-assert-side-effect":                                    Severity.medium,
189     "misc-bool-pointer-implicit-conversion":                      Severity.low,
190     "misc-dangling-handle":                                       Severity.high,
191     "misc-definitions-in-headers":                                Severity.medium,
192     "misc-fold-init-type":                                        Severity.high,
193     "misc-forward-declaration-namespace":                         Severity.low,
194     "misc-forwarding-reference-overload":                         Severity.low,
195     "misc-inaccurate-erase":                                      Severity.high,
196     "misc-incorrect-roundings":                                   Severity.high,
197     "misc-inefficient-algorithm":                                 Severity.medium,
198     "misc-lambda-function-name":                                  Severity.low,
199     "misc-macro-parentheses":                                     Severity.medium,
200     "misc-macro-repeated-side-effects":                           Severity.medium,
201     "misc-misplaced-const":                                       Severity.low,
202     "misc-misplaced-widening-cast":                               Severity.high,
203     "misc-move-const-arg":                                        Severity.medium,
204     "misc-move-constructor-init":                                 Severity.medium,
205     "misc-move-forwarding-reference":                             Severity.medium,
206     "misc-multiple-statement-macro":                              Severity.medium,
207     "misc-new-delete-overloads":                                  Severity.medium,
208     "misc-noexcept-move-constructor":                             Severity.medium,
209     "misc-non-copyable-objects":                                  Severity.high,
210     "misc-redundant-expression":                                  Severity.medium,
211     "misc-sizeof-container":                                      Severity.high,
212     "misc-sizeof-expression":                                     Severity.high,
213     "misc-static-assert":                                         Severity.low,
214     "misc-string-compare":                                        Severity.low,
215     "misc-string-constructor":                                    Severity.high,
216     "misc-string-integer-assignment":                             Severity.low,
217     "misc-string-literal-with-embedded-nul":                      Severity.medium,
218     "misc-suspicious-enum-usage":                                 Severity.high,
219     "misc-suspicious-missing-comma":                              Severity.high,
220     "misc-suspicious-semicolon":                                  Severity.high,
221     "misc-suspicious-string-compare":                             Severity.medium,
222     "misc-swapped-arguments":                                     Severity.high,
223     "misc-throw-by-value-catch-by-reference":                     Severity.high,
224     "misc-unconventional-assign-operator":                        Severity.medium,
225     "misc-undelegated-constructor":                               Severity.medium,
226     "misc-uniqueptr-reset-release":                               Severity.medium,
227     "misc-unused-alias-decls":                                    Severity.low,
228     "misc-unused-parameters":                                     Severity.low,
229     "misc-unused-raii":                                           Severity.high,
230     "misc-unused-using-decls":                                    Severity.low,
231     "misc-use-after-move":                                        Severity.high,
232     "misc-virtual-near-miss":                                     Severity.high,
233     "modernize-avoid-bind":                                       Severity.style,
234     "modernize-deprecated-headers":                               Severity.low,
235     "modernize-loop-convert":                                     Severity.style,
236     "modernize-make-shared":                                      Severity.low,
237     "modernize-make-unique":                                      Severity.low,
238     "modernize-pass-by-value":                                    Severity.low,
239     "modernize-raw-string-literal":                               Severity.style,
240     "modernize-redundant-void-arg":                               Severity.style,
241     "modernize-replace-auto-ptr":                                 Severity.low,
242     "modernize-replace-random-shuffle":                           Severity.low,
243     "modernize-return-braced-init-list":                          Severity.style,
244     "modernize-shrink-to-fit":                                    Severity.style,
245     "modernize-unary-static-assert":                              Severity.style,
246     "modernize-use-auto":                                         Severity.style,
247     "modernize-use-bool-literals":                                Severity.style,
248     "modernize-use-default-member-init":                          Severity.style,
249     "modernize-use-emplace":                                      Severity.style,
250     "modernize-use-equals-default":                               Severity.style,
251     "modernize-use-equals-delete":                                Severity.style,
252     "modernize-use-noexcept":                                     Severity.style,
253     "modernize-use-nullptr":                                      Severity.low,
254     "modernize-use-override":                                     Severity.low,
255     "modernize-use-transparent-functors":                         Severity.low,
256     "modernize-use-using":                                        Severity.style,
257     "mpi-buffer-deref":                                           Severity.low,
258     "mpi-type-mismatch":                                          Severity.low,
259     "clang-analyzer-nullability.NullPassedToNonnull":             Severity.high,
260     "clang-analyzer-nullability.NullReturnedFromNonnull":         Severity.high,
261     "clang-analyzer-nullability.NullableDereferenced":            Severity.medium,
262     "clang-analyzer-nullability.NullablePassedToNonnull":         Severity.medium,
263     "clang-analyzer-nullability.NullableReturnedFromNonnull":     Severity.medium,
264     "clang-analyzer-optin.cplusplus.VirtualCall":                 Severity.medium,
265     "clang-analyzer-optin.mpi.MPI-Checker":                       Severity.medium,
266     "clang-analyzer-optin.performance.Padding":                   Severity.low,
267     "clang-analyzer-optin.portability.UnixAPI":                   Severity.medium,
268     "performance-faster-string-find":                             Severity.low,
269     "performance-for-range-copy":                                 Severity.low,
270     "performance-implicit-cast-in-loop":                          Severity.low,
271     "performance-implicit-conversion-in-loop":                    Severity.low,
272     "performance-inefficient-algorithm":                          Severity.medium,
273     "performance-inefficient-string-concatenation":               Severity.low,
274     "performance-inefficient-vector-operation":                   Severity.low,
275     "performance-move-const-arg":                                 Severity.medium,
276     "performance-move-constructor-init":                          Severity.medium,
277     "performance-noexcept-move-constructor":                      Severity.medium,
278     "performance-type-promotion-in-math-fn":                      Severity.low,
279     "performance-unnecessary-copy-initialization":                Severity.low,
280     "performance-unnecessary-value-param":                        Severity.low,
281     "readability-avoid-const-params-in-decls":                    Severity.style,
282     "readability-braces-around-statements":                       Severity.style,
283     "readability-container-size-empty":                           Severity.style,
284     "readability-delete-null-pointer":                            Severity.style,
285     "readability-deleted-default":                                Severity.style,
286     "readability-else-after-return":                              Severity.style,
287     "readability-function-size":                                  Severity.style,
288     "readability-identifier-naming":                              Severity.style,
289     "readability-implicit-bool-cast":                             Severity.style,
290     "readability-implicit-bool-conversion":                       Severity.style,
291     "readability-inconsistent-declaration-parameter-name":        Severity.style,
292     "readability-misleading-indentation":                         Severity.low,
293     "readability-misplaced-array-index":                          Severity.style,
294     "readability-named-parameter":                                Severity.style,
295     "readability-non-const-parameter":                            Severity.style,
296     "readability-redundant-control-flow":                         Severity.style,
297     "readability-redundant-declaration":                          Severity.style,
298     "readability-redundant-function-ptr-dereference":             Severity.style,
299     "readability-redundant-member-init":                          Severity.style,
300     "readability-redundant-smartptr-get":                         Severity.style,
301     "readability-redundant-string-cstr":                          Severity.style,
302     "readability-redundant-string-init":                          Severity.style,
303     "readability-simplify-boolean-expr":                          Severity.medium,
304     "readability-static-accessed-through-instance":               Severity.style,
305     "readability-static-definition-in-anonymous-namespace":       Severity.style,
306     "readability-uniqueptr-delete-release":                       Severity.style,
307     "clang-analyzer-security.FloatLoopCounter":                   Severity.medium,
308     "clang-analyzer-security.insecureAPI.UncheckedReturn":        Severity.medium,
309     "clang-analyzer-security.insecureAPI.getpw":                  Severity.medium,
310     "clang-analyzer-security.insecureAPI.gets":                   Severity.medium,
311     "clang-analyzer-security.insecureAPI.mkstemp":                Severity.medium,
312     "clang-analyzer-security.insecureAPI.mktemp":                 Severity.medium,
313     "clang-analyzer-security.insecureAPI.rand":                   Severity.medium,
314     "clang-analyzer-security.insecureAPI.strcpy":                 Severity.medium,
315     "clang-analyzer-security.insecureAPI.vfork":                  Severity.medium,
316     "clang-analyzer-unix.API":                                    Severity.medium,
317     "clang-analyzer-unix.Malloc":                                 Severity.medium,
318     "clang-analyzer-unix.MallocSizeof":                           Severity.medium,
319     "clang-analyzer-unix.MismatchedDeallocator":                  Severity.medium,
320     "clang-analyzer-unix.Vfork":                                  Severity.medium,
321     "clang-analyzer-unix.cstring.BadSizeArg":                     Severity.medium,
322     "clang-analyzer-unix.cstring.NullArg":                        Severity.medium,
323     "clang-analyzer-valist.CopyToSelf":                           Severity.medium,
324     "clang-analyzer-valist.Uninitialized":                        Severity.medium,
325     "clang-analyzer-valist.Unterminated":                         Severity.medium,
326             ];
327 
328     import colorize : Color, Background, Mode;
329 
330     severityColor = [
331         Severity.style: SeverityColor(Color.light_cyan, Background.black, Mode.init_),
332         Severity.low: SeverityColor(Color.light_blue, Background.black, Mode.bold),
333         Severity.medium: SeverityColor(Color.light_yellow, Background.black, Mode.init_),
334         Severity.high: SeverityColor(Color.red, Background.black, Mode.bold),
335         Severity.critical: SeverityColor(Color.magenta, Background.black, Mode.bold),
336     ];
337     // dfmt on
338 }
339 
340 struct CountErrorsResult {
341     import code_checker.engine.types : Severity;
342 
343     private {
344         int total;
345         int[Severity] score_;
346     }
347 
348     /// Returns: the score when summing up the found occurancies.
349     int score() @safe pure nothrow const @nogc scope {
350         int sum;
351         // just chose some numbers. The intent is that warnings should be a high penalty
352         foreach (kv; score_.byKeyValue) {
353             final switch (kv.key) {
354             case Severity.style:
355                 sum -= kv.value;
356                 break;
357             case Severity.low:
358                 sum -= kv.value * 2;
359                 break;
360             case Severity.medium:
361                 sum -= kv.value * 5;
362                 break;
363             case Severity.high:
364                 sum -= kv.value * 10;
365                 break;
366             case Severity.critical:
367                 sum -= kv.value * 100;
368                 break;
369             }
370         }
371 
372         return sum;
373     }
374 
375     void put(const Severity s) {
376         total++;
377 
378         if (auto v = s in score_)
379             (*v)++;
380         else
381             score_[s] = 1;
382     }
383 
384     auto toRange() const {
385         import std.algorithm : map, sort;
386         import std.array : array;
387         import std.format : format;
388 
389         return score_.byKeyValue.array.sort!((a, b) => a.key > b.key)
390             .map!(a => format("%s %s", a.value, a.key));
391     }
392 }
393 
394 @("shall sort the error counts")
395 unittest {
396     import std.traits : EnumMembers;
397     import code_checker.engine.types : Severity;
398     import unit_threaded;
399 
400     CountErrorsResult r;
401     foreach (s; [EnumMembers!Severity])
402         r.put(s);
403 
404     r.toRange.shouldEqual(["1 critical", "1 high", "1 medium", "1 low", "1 style"]);
405 }
406 
407 /** Apply `fn` on the diagnostic messages.
408  *
409  * The return value from fn replaces the message. This makes it possible to
410  * rewrite a message if needed.
411  *
412  * Params:
413  *  diagFn = mapped onto a diagnostic message
414  *  lines = an input range of lines to analyze for diagnostic messages
415  *  w = output range that the resulting log is written to.
416  */
417 void mapClangTidy(alias diagFn, Writer)(string[] lines, ref scope Writer w) {
418     import std.algorithm : startsWith;
419     import std.regex : ctRegex, matchFirst;
420     import std..string : startsWith;
421     import std.range : put;
422 
423     auto re_error = ctRegex!(`.*:\d*:.*error:.*\[(.*)\]`);
424 
425     foreach (l; lines) {
426         auto m = matchFirst(l, re_error);
427 
428         if (m.length > 1) {
429             const s = classify(m[1]);
430             put(w, diagFn(s, l));
431         } else {
432             put(w, l);
433         }
434     }
435 }
436 
437 /// Returns: the classification of the diagnostic message.
438 Severity classify(string diagnostic_msg) {
439     import std..string : startsWith;
440 
441     if (auto v = diagnostic_msg in diagnosticSeverity) {
442         return *v;
443     }
444 
445     // this is a fallback when new rules are added to clang-tidy but
446     // they haven't been thoroughly analyzed in
447     // `code_checker.engine.builtin.clang_tidy_classification`.
448     if (diagnostic_msg.startsWith("readability-"))
449         return Severity.style;
450     else if (diagnostic_msg.startsWith("clang-analyzer-"))
451         return Severity.high;
452 
453     return Severity.medium;
454 }
455 
456 /**
457  * Params:
458  *  predicate = param is the classification of the diagnostic message. True means that it is kept, false thrown away
459  * Returns: a range of rules to inactivate that are below `s`
460  */
461 auto filterSeverity(alias predicate)() {
462     import std.algorithm : filter, map;
463 
464     // dfmt off
465     return diagnosticSeverity
466         .byKeyValue
467         .filter!(a => predicate(a.value))
468         .map!(a => a.key);
469     // dfmt on
470 }
471 
472 /// Returns: severity as a string with colors.
473 string color(Severity s) {
474     import std.conv : to;
475     static import colorize;
476 
477     SeverityColor sc;
478 
479     if (auto v = s in severityColor) {
480         sc = *v;
481     }
482 
483     return colorize.color(s.to!string, sc.c, sc.bg, sc.m);
484 }